<?php

// ---< Variables >---     -     -     -     -     -     -     -     -     -     -     -     -     -     -     -     -     -     -     -     -     -    | 160 |

$fuzzy      = true;                                     // toggle using fuzzier search patterns (overwritten by -f)
$path       = "";                                       // path to media files (overwritten by -p /path/)
$except     = "! Exclude";                              // Optional: Exclude dir from recursive search
// NB: This will be deprecated in the near future, I indent to support YAMJ-compatible .mjbignore files instead.
$ui         = false;                                    // toggle user input when automatic matching fails (overwritten by -i)
$usetagID   = 1;                                        // set behaviour if ID is found in filename, 0 = ignore ID, 1 = skip file, 2 = write ID to nfo

$nfo_ext    = ".info_TEST";                                  // extension for output nfo
$media_dir  = '[\w\d]+\.([\w\d]+\.?)+(-([\w\d]+))?';    // regular expression (case-sensitive), remove trailing ? to force group names
$testfile   = "";                                       // Optional: set to filename to limit execution to specific file(s)
$log_debug  = true;                                     // toggle logging debug messages
$dg_fetcher = false;                                    // toggle logging detailed file fetcher messages
$dg_norm    = false;                                    // toggle logging detailed normalize_string messages
$dg_parser  = false;                                    // toggle logging detailed parser messages
$min_size   = '100';                                    // Optional: minimum filesize in MB to match
$excl_max   = '125';                                    // Optional: maximum filesize in MB to exclude if excludes is matched
$excludes   = array('sample');                          // lowercase (case-insensitive)
$ignores    = array('^cd\d$');                          // regular expression (case insensitive)
$customtags = array('ID' => '(\[ID (\w+)[ -]((tt)?\d+)\])',
                    'CD' => '(\[((CD|DIS[CK]|PART)\d)\])',
                    'SET' => '(\[SET ([^]]+)\])');      // regular expression (case insensitive)
$episodes   = array('[sS]\d{2}[eE]\d{2}',
                    '^(.*\.)?[sS]\d{2}(\..*)$',
                    '\.\d{1,2}x\d{2}',
                    'Ep\.\d{2}',
                    '[sS]eason\.?\d{1,2}',
                    '[.-]\d{3}.*(-amc|-lol|-ositv)\.[\w\d]{3}',
                    '[.-]\d{3}(\.hdtv)');               // regular expression (case sensitive) [I suspect this last regex may possibly cause false positives]
$media_ext  = array('.avi' => true,
                    '.mkv' => true,
                    '.mp4' => true);                    // lowercase (case-insensitive)



// ---< Script >--- Here be dragons

error_reporting(E_ALL ^ E_NOTICE ^ E_WARNING);

$shortopts     = 'efhip:';
$longopts     = array('purge');
$options     = getopt($shortopts, $longopts);

foreach (array_keys($options) as $opt) switch ($opt) {
    case 'h':
    case 'help':
        help();
        break;

    case 'e':
        $easyui = true;
        break;
    
    case 'f':
        $fuzzy = true;
        break;
    
    case 'i':
        $ui = true;
        break;
    
    case 'p':
        $path = rtrim($options['p'], '/');
        break;
    
    case 'purge':
        $purge = true;
        break;
}

/* Initiate script */
$imdbObj     = new Imdb();
$log         = new Logging();

$timer[init] = date('H:i:s');
$log->lsetdebug($log_debug);

$counter0 = 0; // Auto detects
$counter1 = 0; // Query failed
$counter2 = 0; // NFO found
$counter3 = 0; // User input URL

/* Check user input */
if ( !$path ) { $log->lwrite("You did not specify a path"); exit(1); }
if ( !is_dir($path) ) { $log->lwrite($path." is not a valid path"); exit(1); }
if ( $easyui && $ui ) { $log->lwrite("Error: -e and -i detected, disabling -i"); $ui = false; }

/* If easyui is on, prepare output file */
if ($easyui) $ezui = new Logging();
if ($ezui) $ezui->lfile("easyui.html");
if ($ezui) $ezui->lhtmlinit();

/* Get list of media files */

$files = get_media($path);
$timer[found] = date('H:i:s');

/* Get imdb id */
foreach ($files as $file) {
    
    // Build nfo path
    $nfo = str_replace(strrchr($file,'.'), $nfo_ext, $file);

    // Strip $path
    $file_dirs = str_replace($path."/", '', $file);
    
    // Explode remaining path
    $dirs = array_reverse(explode('/', $file_dirs));
    
    /* At this point, here are what our relevant variables and arrays are populated with:
    $file       = /home/user/movies/folder/subfolder/mediafile.ext
    $nfo        = /home/user/movies/folder/subfolder/mediafile.info
    $path       = /home/user/movies
    $file_dirs  = folder/subfolder/mediafile.ext
    $dirs[0]    = mediafile.ext
    $dirs[1]    = subfolder
    $dirs[2]    = folder */

    // Check filename for custom tags and extract iMDB ID if possible
    foreach ($customtags as $key=>$value) {
        while ( preg_match("/$value/", $dirs[0], $match) ) {
            if ($usetagID != 0 && $key == "ID" && $match[2] == "IMDB") {
                if ($usetagID == 2) {
                    if (!file_put_contents($nfo, "http://akas.imdb.com/title/{$match[2]}/")) { $log->lwrite("ERR Error writing {$nfo}"); } else { $log->ldebug(" >  ID matched in filename, writing to NFO: {$dirs[0]}"); }
                } else if ($usetagID == 1) {
                    $log->ldebug(" X  ID matched in filename, skipping: {$dirs[0]}");
                }
                continue(3);
            }
            $dirs[0] = str_ireplace("$match[2]", "", $dirs[0]);
            if ($log) { $log->ldebug("customtags($key).stripped: {$match[2]}"); }
        }
    }
    
    // Skip TV episodes
    // TODO Support TV episodes
    if (preg_match('/'.implode('|', $episodes).'/', $dirs[0])) {
            $log->ldebug(" X  Skipping TV episode: {$dirs[0]}");
            continue;
    }
    
    // Select only media files within folders
    $i=1;

    // Waaaiiittt! You forgot about files that are in the root path!
    if ($dirs[0] == $file_dirs ) {
        $i=0;
    }
    
    // Okay let's do this!
    while($i < count($dirs)) {

        // Debugging: Set testfile to desired filename to limit execution
        if ($testfile && $dirs[0] != $testfile ) { continue(2); }
    
        // Check for nfo
        if (file_exists($nfo)) {
        
            // Are we purging?
            if ( $purge && filesize($nfo) < 40 && filesize($nfo) > 35 ) {
                $log->lwrite(" .  Removing {$nfo}");
                unlink($nfo);
                continue(2);
            }
        
            // Yo we can skip this one
            $log->lwrite(" .  {$dirs[0]} (NFO found)");
            if ( filesize($nfo) < 35 ) $log->lwrite(" X  WARNING: NFO is smaller than expected: {$nfo}");
            if ( filesize($nfo) > 40 ) $log->lwrite(" X  WARNING: NFO is bigger than expected: {$nfo}");
            
            $counter2++;
            continue(2);
        } else if ( $purge ) { continue(2); }
        
        // Announce new file to process
        ($skip)?$skip = false:$log->lwrite("NEW {$dirs[0]}");
        
        // Folder name found
        $log->lwrite("--- ParentDir:  {$dirs[$i]}");
        $folder = normalize_string($dirs[$i]);

        if ($folder != $dirs[$i]) {
            $log->lwrite("~~~ Normalized: {$folder}");
        }

        // Skip TV episodes
        if (preg_match('/'.implode('|', $episodes).'/', $folder)) {
            $log->ldebug(" X  Skipping TV episode: {$dirs[0]}");
            continue(2);
        }
        
        // Skip $ignores
        if (preg_match('/'.implode('|', $ignores).'/i', $folder)) {
            $log->ldebug("    /{$dirs[$i]}/ matched ignores, we need to go deeper.");
            $skip = true;
            $i++;
            continue;
        }
        
        // Check if folder matches $media_dir pattern and we should use filename instead
        if (!preg_match('/'.$media_dir.'/i', $folder)) {
            $log->lwrite(" -  {$dirs[$i]} doesn't match $media_dir, parsing filename");
            $folder = normalize_string($dirs[0]);
            $log->lwrite("~~~ Normalized: {$folder}");
        }
        
        // Extract title from chosen name
        $elements = parse_rls($folder);
        $query = format_search($elements[title], $elements[year]);
        
        // Query iMDB
        $log->lwrite("--> iMDB Query: {$query}");
        $movieInfo = $imdbObj->get($query);
        
        // Unsuccessful, attempt a fuzzy parse [-f]
        if (!$movieInfo[url] && $fuzzy) {
            $elements = parse_rls($folder, true);
            $query = format_search($elements[title], $elements[year]);
            $log->lwrite("--> iMDB Fuzzy: {$query}");
            $movieInfo = $imdbObj->get($query);
        }
        
        // If unsuccesful, output error or query for user input
        if (!$movieInfo[url]) {
        
            // Damn :(
            $log->lwrite("ERR iMDB scraping failed.");
            $counter1++;
            
            // Add failed query to the easyui html [-e]
            if ($ezui) $ezui->lhtml("<a href=\"http://akas.imdb.com/find?q=".urlencode($query)."\">{$query}</a> ({$dirs[$i]})<br />");
            
            // Query the user for the iMDB URL [-i]
            if ($ui) {
                print("INTERACTIVE MODE: Please enter the corresponding iMDB URL:");
                $userinput = chop(fgets(STDIN));
                if ($imdbObj->isValidURL($userinput) ) {
                    $log->lwrite("--- User-input URL: {$userinput}");
                    $movieInfo[url] = $userinput;
                    $counter3++;
                } else {
                    $log->lwrite("ERR Invalid URL: {$userinput}");
                    continue(2);
                }
            } else {
                continue(2);
            }
        }
        
        // URL Found
        if ($movieInfo[url]) $log->lwrite("\o/ URL: {$movieInfo[url]}");
        $counter0++;
        
        // Output URL to nfo
        if (!file_put_contents($nfo, $movieInfo[url])) { $log->lwrite("ERR Error writing {$nfo}"); } else { $log->ldebug(" >  {$nfo}"); }
        
        // Sleep for 0.25s
        usleep(250000);
        $i++;
        continue(2);
    }
}

// Exit gracefully
$timer[end] = date('H:i:s');
$log->lwrite("iMDB URL Fetching complete:");

// Finish up the HTML if it's being written
if ($ezui) $ezui->lhtml("</body>");
if ($ezui) $ezui->lhtml("</html>");
if ($ezui) $log->lwrite("Easy UI output complete");

// Output some timers to show off
foreach ($timer as $key=>$value) {
    $log->lwrite("   {$value}: {$key}");
}

// Output some stats (more showing off)
$log->lwrite("Successfully matched: {$counter0}");
$log->lwrite("No match found/given: {$counter1}");
$log->lwrite("NFO found:            {$counter2}");
$log->lwrite("User provided:        {$counter3}");
$log->lwrite("All done, goodnight :)");

fgets(STDIN);
exit(0);

// ---< Functions >---

/*     Return array of media files in $path */
function get_media($dir) {
    
    /* Returns an array of paths to media files in $path
     * Requires matching $media_ext extensions (avi, mkv, etc.)
     * Optional: Excludes strpos matches of $excludes (optionally checking maximum size)
     * Optional: Excludes files below a minimum size */
    
    // Import vars
    global $media_ext;
    global $except;
    global $excludes;
    global $excl_max;
    global $min_size;
    
    global $dg_fetcher;
    if ($dg_fetcher) global $log;
    
    // Convert MiB to B
    $excl_bytes = $excl_max * 1048576;
    $min_bytes = $min_size * 1048576;
    
    if ($log) {
        $log->ldebug('get_media().fetching.files...');
        if ($excludes && $excl_bytes) { $log->ldebug('get_media().matching.excludes.with.max.size');
        } else if ($excludes) {         $log->ldebug('get_media().matching.excludes.without.max.size');
        } else {                        $log->ldebug('get_media().matching.excludes.disabled'); }
        if ($min_bytes) {               $log->ldebug('get_media().matching.minimum.size');
        } else {                        $log->ldebug('get_media().matching.minimum.size.disabled'); }
    }
    
    $path = '';
    $stack[] = $dir;
    while ($stack) {
        $thisdir = array_pop($stack);

        // Skip excluded directories
        if (strpos($thisdir, $except)) {
            if ($log) { $log->ldebug("get_media().excluded.path: {$thisdir}"); }
            continue;
        }
        
        if ($dircont = scandir($thisdir)) {
            $i=0;
            while (isset($dircont[$i])) {
                if ($dircont[$i] !== '.' && $dircont[$i] !== '..') {
                    $current_file = "{$thisdir}/{$dircont[$i]}";
                    if (is_file($current_file)) {
                        $ext = strtolower(strrchr($current_file,'.'));

                        // Validate extensions using array keys
                        if ($media_ext[$ext]) {

                            // Check if file is a windows deleted file
                            if (strpos($current_file, '$') === 3 ) {
                                if ($log) { $log->ldebug('get_media(excluded).deleted.file: '.$current_file); }
                                $i++;
                                continue;
                            }
                            
                            // Check minimum size
                            if ($min_bytes) {
                                if (filesize($current_file) < $min_bytes && filesize($current_file) > 0) {
                                    if ($log) { $log->ldebug("get_media(excluded).min.size: [".filesize($current_file)."] {$current_file}"); }
                                    $i++;
                                    continue;
                                }
                            }
                            
                            // Check for exclusion pattern and under $excl_max MB
                            if ($excludes && $excl_bytes) {
                                if ((strpos_arr(strtolower($current_file), $excludes)) && filesize($current_file) < $excl_bytes) {
                                    if ($log) { $log->ldebug("get_media(excluded).match: [".filesize($current_file)."] {$current_file}"); }
                                    $i++;
                                    continue;
                                }
                            
                            // Check for exclusion pattern regardless of size
                            } else if ($excludes) {
                                if (strpos_arr(strtolower($current_file), $excludes)) {
                                    if ($log) { $log->ldebug("get_media(excluded).match: {$current_file}"); }
                                    $i++;
                                    continue;
                                }
                            }

                            // Add entry to array
                            if ($log) { $log->ldebug("get_media().found: {$current_file}"); }
                            $path[] = "{$thisdir}/{$dircont[$i]}";
                        }
                    } elseif (is_dir($current_file)) {
                        /* $path[] = "{$thisdir}/{$dircont[$i]}"; Ignore folders */
                        $stack[] = $current_file;
                    }
                }
                $i++;
            }
        }
    }

    // Windows listings are reversed
    if ($log) { $log->ldebug('get_media().sorting.files'); }
    sort($path);
    
    if ($log) { $log->ldebug('get_media().completed'); }
    return $path;
}

/* strpos that takes an array of values to match against a string */
function strpos_arr($haystack, $needle) {
    if(!is_array($needle)) $needle = array($needle);
    foreach($needle as $what) {
        if(($pos = strpos($haystack, $what))!==false) return $pos;
    }
    return false;
}

/* Build iMDB search string */
function format_search($string, $year = 0) {
    while (strpos($string, "..") > 0) { print("Stripping duplicate ..\n"); $string = str_replace('..', '.', $string); }
    $string = str_ireplace(".", " ", $string);
    $string = trim(ucwords($string));
    if ($year != 0) $string .= " (".$year.")";
    return $string;
}

/* Normalize release name */
function normalize_string($string) {

    global $dg_norm;
    if ($dg_norm) global $log;

    global $media_ext;
    foreach ($media_ext as $key=>$value) {
        $keys[] = $key;
    }
    $extensions = '('.implode('|', $keys).')';
    
    // Store extension
    if ( preg_match("/$extensions$/i", $string, $match) ) {
        $string = str_ireplace("$match[1]", "", $string);
        $extension = $match[1];
        if ($log) { $log->ldebug('normalize_string().$string: '. $string .'('.$extension.')'); }
    }
    
    // Move Anime group names from the beginning to the end
    if ( preg_match("/^\[([\w\d-&]+)\]/", $string, $match) ) {
        $string = str_replace("$match[1]", "", $string);
        $string .= "-" . str_replace(array('-', '&'), '.', $match[1]);
        if ($log) { $log->ldebug('normalize_string().$string: '.$string); }
    }
    
    // replace spacers with .
    $string = str_replace(array(' ', '_', ',', '+'), '.', $string);
    if ($log) { $log->ldebug('normalize_string().$string: '.$string); }
    
    // strip illegal chars
    $string = str_replace(array('\'', '.(', ').', '.[', '].'), '.', $string);
    $string = str_replace(array('(', ')', '[', ']', ':', ';'), '.', $string);
    if ($log) { $log->ldebug('normalize_string().$string: '.$string); }

    // strip duplicate whitespace/punctuation
    $string = preg_replace('{(\s|\.)\1+}', '$1', $string);
    if ($log) { $log->ldebug('normalize_string().$string: '.$string); }
    
    // fix .-.
    $string = str_replace(array('.-', '-.'), '-', $string);
    if ($log) { $log->ldebug('normalize_string().$string: '.$string); }
    
    // fix duplicate "-"
    while (substr_count($string, "-") > 1) $string = preg_replace('/-/', '.', $string, 1);
    if ($log) { $log->ldebug('normalize_string().$string: '.$string); }
    
    // fix non-group delimiting "-"
    if (!preg_match("/-[\w\d]+$/", $string) ) $string = str_replace('-', '.', $string);
    if ($log) { $log->ldebug('normalize_string().$string: '.$string); }
    
    // Restore extension
    $string .= $extension;
    if ($log) { $log->ldebug('normalize_string().$string: '.$string); }
    
    return $string;
}

/* Parse release name */
function parse_rls($string, $fuzzy = false) {
    
    // TODO Aggressive strip should remove anything in [], possibly also ()
    
    global $dg_parser;
    if ($dg_parser) global $log;
    
    global $media_ext;
    foreach ($media_ext as $key=>$value) {
        $keys[] = $key;
    }
    
    //Strip irrelevant tags
    $tags = '\.(Boxset|Criterion(\.Edition)?|DOCU|FS|HQ|(CE\.)?(i|I)NTERNAL|(i|I)NT|L(i|I)NE|NTSC|OAR|PAL|(REAL\.)?PROPER|READNFO|REMASTERED(\.VERSION)?|REPACK|RERiP|RETAiL|RERiP|READ\.?NFO|RETAIL|(CE\.)?UNCUT|UNRATED|Unrated|WS)[\.-]';

    while ( preg_match("/$tags/", $string, $match) ) {
        $string = str_ireplace(".$match[1]", "", $string);
        if ($log) { $log->ldebug('parse_rls(tag).stripping: '.$match[1]); }
    }
    
    //Fix individual annoyances
    $fixes = '\.(Hive|VH)-';

    while ( preg_match("/$fixes/", $string, $match) ) {
        $string = str_ireplace(".$match[1]", "", $string);
        if ($log) { $log->ldebug('parse_rls(fix).stripping: '.$match[1]); }
    }
    
    // Strip anime hex IDs
    while ( preg_match("/\.([A-F0-9]{8})/", $string, $match) ) {
        $string = str_ireplace(".$match[1]", "", $string);
        if ($log) { $log->ldebug('parse_rls(hex).stripping: '.$match[1]); }
    }
    
    /* Extrapolate elements */
    $extensions = '('.implode('|', $keys).')$';
    $audios = '\.(AAC|AC3|DD5\.?1|DTS(\.[A-Z]{2})?|FLAC)([\.-][\w\d\.-]+)?$';
    $codecs = '\.(DiVX|XviD|x264|h264)([\.-][\w\d\.-]+)?$';
    $sources = '\.(DVDSCR|DVDRip|Blu\.?Ray|BRRip|BDRip|R5|TS|CAM|VODRip|HDTV|PDTV|PPVRip)([\.-][\w\d\.-]+)?$';
    $resolutions = '\.(720p|1080p|\d{3,4}x\d{3,4})([\.-][\w\d\.-]+)?$';
    $editions = '\.(COLLECTION|DirCut|Directors\.Cut|Dual\.Audio|EXTENDED(\.Cut|\.EDITION|\.Version)?|L(i|I)M(i|I)TED|Limited|Special\.Edition|STV|THEATRiCAL|Unrated)([\.-][\w\d\.-]+)?$';
    $years = '\.(\d{4})([\.-][\w\d\.-]+)?$';
    
    // Extract extension
    if ( preg_match("/$extensions/i", $string, $match) ) {
        $grabValue['extension'] = $match[1];
        $string = str_replace("$match[1]", "", $string);
        if ($log) { $log->ldebug('parse_rls(ext).stripping: '.$match[1]); }
    }

    // Extract audio
    if ( preg_match("/$audios/i", $string, $match) ) {
        $grabValue['audio'] = $match[1];
        $string = str_ireplace(".$match[1]", "", $string);
        if ($log) { $log->ldebug('parse_rls(aud).stripping: '.$match[1]); }
    }
    
    // Extract codec
    if ( preg_match("/$codecs/i", $string, $match) ) {
        if (!$position || strpos($string, $match[1]) < $position) $position = strpos($string, $match[1]);
        $grabValue['codec'] = $match[1];
        $string = str_ireplace(".$match[1]", "", $string);
        if ($log) { $log->ldebug('parse_rls(cdc).stripping: '.$match[1]); }
    }
    
    // Extract source
    if ( preg_match("/$sources/i", $string, $match) ) {
        if (!$position || strpos($string, $match[1]) < $position) $position = strpos($string, $match[1]);
        $grabValue['source'] = $match[1];
        $string = str_ireplace(".$match[1]", "", $string);
        if ($log) { $log->ldebug('parse_rls(sou).stripping: '.$match[1]); }
    }

    // Extract resolution
    if ( preg_match("/$resolutions/i", $string, $match) ) {
        if (!$position || strpos($string, $match[1]) < $position) $position = strpos($string, $match[1]);
        $grabValue['resolution'] = $match[1];
        $string = str_replace(".$match[1]", "", $string);
        if ($log) { $log->ldebug('parse_rls(res).stripping: '.$match[1]); }
    }

    // Extract edition (case sensitive)
    if ( preg_match("/$editions/i", $string, $match) ) {
        if (!$position || strpos($string, $match[1]) < $position) $position = strpos($string, $match[1]);
        $grabValue['edition'] = $match[1];
        $string = str_replace(".$match[1]", "", $string);
        if ($log) { $log->ldebug('parse_rls(edi).stripping: '.$match[1]); }
    }

    // Extract year
    if ( preg_match("/$years/", $string, $match) ) {
        if (!$position || strpos($string, $match[1]) < $position) $position = strpos($string, $match[1]);
        $grabValue['year'] = $match[1];
        $string = str_replace(".$match[1]", "", $string);
        if ($log) { $log->ldebug('parse_rls(yrs).stripping: '.$match[1]); }
    }

    // Extract group name
    if ( preg_match("/-([\w\d]+)$/", $string, $match) ) {
        $grabValue['group'] = $match[1];
        $string = str_replace("-$match[1]", "", $string);
        if ($log) { $log->ldebug('parse_rls(grp).stripping: '.$match[1]); }
    }
    
    if ( $fuzzy && $position > 0 ) {
        if ($log) { $log->ldebug('parse_rls(fuz).stripping: '.substr($string, $position)); }
        $string = substr($string, 0, $position);
    }
    
    if ($log) { $log->ldebug('parse_rls(end).remaining: '.$string); }
    $grabValue['title'] = $string;

    return $grabValue;
}
    
// ---< Classes >---

class Imdb {
    
    /**
     * This Method Grabs the info from IMDB website and returns it in an assoc array format, false on failure
     * @return array|boolean
     * @param  string $url
     */
    public function get($url) {
        
        if( !$this->isValidURL($url) ) {
            $url = $this->getImdbURL($url);
        }
        
        $imdbDom  = new DomDocument();
        $imdbLoad = $imdbDom->loadHTMLFile($url);
        if( $imdbLoad === false ) {
            return false;
        }

        $grabValue['url'] = $url;
        return $grabValue;
    }
    
    /**
     * Checks if a URL is a valid URL or not
     *
     * @return boolean 
     * @param  string  $url
     **/
    public function isValidURL($url) {
        // a simple regex
        $matchCount = preg_match("/(www\.)?imdb\.com\/title\/[A-Za-z0-9]+/i", $url);
        return !($matchCount < 1);
    }
    
    /**
     * Grab a proper URL from a search query
     *
     * @return string/boolean     $url on success and false on failure
     * @param  string             $url
     */
    public function getImdbURL($url) {
        $queryStr       = '//p[@style]/b/a';
        $validTitleStr  = "//head/link[@rel='canonical']"; 
        $searchURL  = 'http://akas.imdb.com/find?q='.urlencode($url);
        $searchDom  = new DomDocument();
        $searchLoad = $searchDom->loadHTMLFile($searchURL);

        $xpath      = new DomXPath($searchDom);
        // check to see if Imdb has directly redirected to the movie page.
        $linkHrefURL  = $xpath->query($validTitleStr)->item(0)->getAttribute('href');
        if($this->isValidURL($linkHrefURL) ) {
            return $linkHrefURL;
        } 
        
        if($xpath->query($queryStr)->length > 0 ) {
            return 'http://akas.imdb.com'.$xpath->query($queryStr)->item(0)->getAttribute('href');
        } else {
            return false;
        }
    }
}

class Logging{
    /**
     * Logging class:
     * - contains lfile, lopen and lwrite methods
     * - lfile sets path and name of log file
     * - lwrite will write message to the log file
     * - ldebug will also write messages to the log file if debugging is enabled
     * - lhtml will divert it's output to an html file
     * - first call of the lwrite will open log file implicitly
     * - message is written with the following format: hh:mm:ss (script name) message
     */
    
    // define default log file
    private $log_file = 'iMDB-ID-Fetcher.log';
    // define default debug behaviour
    private $log_debug = false;
    // define file pointer
    private $fp = null;
    // set log file (path and name)
    public function lfile($path) {
        $this->log_file = $path;
    }
    // set debug behaviour
    public function lsetdebug($bool) {
        $this->log_debug = $bool;
    }
    // open log file
    private function lopen() {
        // define log file path and name
        $lfile = $this->log_file;
        // open log file for writing only;
        $this->fp = fopen($lfile, 'w') or exit("Can't open $lfile!");
    }

    // write message to the log file
    public function lwrite($message) {
        // if file pointer doesn't exist, then open log file
        if (!$this->fp) $this->lopen();
        // define script name
        $script_name = pathinfo($_SERVER['PHP_SELF'], PATHINFO_FILENAME);
        // define current time
        $time = date('H:i:s');
        // write current time, script name and message to the log file
        fwrite($this->fp, "$time ($script_name) $message\r\n");
        // print message to output
        print($message."\r\n");
    }
    
    // write message to the debug log
    public function ldebug($message) {
        if (!$this->log_debug) return;
        if (!$this->fp) $this->lopen();
        $script_name = pathinfo($_SERVER['PHP_SELF'], PATHINFO_FILENAME);
        $time = date('H:i:s');
        fwrite($this->fp, "$time ($script_name) DEBUG: $message\r\n");
        print($message."\r\n");
    }
    
    // write message to the html output
    public function lhtml($message) {
        if (!$this->fp) $this->lopen();
        fwrite($this->fp, "$message\r\n");
    }
    
    // write html headers
    public function lhtmlinit() {
        $this->lhtml('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"');
        $this->lhtml('"http://www.w3.org/TR/html4/loose.dtd">');
        $this->lhtml('<html lang="en">');
        $this->lhtml('<head>');
        $this->lhtml('<meta http-equiv="content-type" content="text/html; charset=utf-8">');
        $this->lhtml('<title>iMDB ID Fetcher Easy UI</title>');
        $this->lhtml('</head>');
        $this->lhtml('<body>');
    }
}


/* Display help, located here because heredoc breaks syntax highlighting */
function help() {
echo <<< EOT
iMDB ID Fetcher
Usage: iMDB-ID-Fetcher.php [options]

Options:
 -e        EasyUI mode, outputs failed queries to html
 -h        Display this help message
 -i        Interactive, prompts for URLs if detection failed
 -p /path/    Path to media files

ProTip: 

1. Run this script once automatically to take care of any easy pickings.
To do so, edit iMDB-ID-Fetcher.bat and change the command to:

php iMDB-ID-Fetcher.php -p "D:/path/to/movies/" -f -e

2. An easyui.html file should have been generated containing any failed matches.
Open it in your browser then edit and run iMDB-ID-Fetcher.bat again:

php iMDB-ID-Fetcher.php -p "D:/path/to/movies/" -f -i

This 2nd run should prompt you for any URLs that couldn't be detected.
Each movie file in /path/to/movies/ should now have a corresponding .nfo :)
EOT;
fgets(STDIN);
exit(0);
}

?>